﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Microsoft.Win32;
using System.ServiceProcess;
using System.Collections;
using System.Reflection;
using System.Configuration.Install;
using System.Diagnostics;
using CNative.WebApi.Utils;

namespace CNative.WebApi.ServiceProcess
{
    public class ServiceAPI
    {
        #region isServiceIsExisted
        static List<ServiceController> services = null;
        /// <summary>  
        /// 检查服务存在的存在性  
        /// </summary>  
        /// <param name=" NameService ">服务名</param>  
        /// <returns>存在返回 true,否则返回 false;</returns>  
        public static bool isServiceIsExisted(string NameService)
        {
            try
            {
                if (services == null || services.Count == 0)
                    services = new List<ServiceController>(ServiceController.GetServices());//.OrderBy(o=>o.DisplayName).ToList();
                if (services.Find(s => s.ServiceName.ToLower() == NameService.ToLower()) != null)
                {
                    return true;
                }
            }
            catch { }
            return false;
        }
        #endregion
        #region GetServiceController
        public static ServiceController GetServiceController(string NameService)
        {
            var sc = new ServiceController(NameService);
            if (sc != null)
            {
                return sc;
            }
            return null;
        }
        #endregion

        #region 安装服务
        /// <summary>    
        /// 安装服务    
        /// </summary>    
        public static bool InstallService(string ServiceFullName)
        {
            bool flag = true;
            var ServiceName = GetFileName(ServiceFullName); 
            if (!isServiceIsExisted(ServiceName))
            {
                try
                {
                     flag = InstallmyService(new Hashtable(), ServiceFullName);
                    //var ss = Funs.RunExe(GetFilePath(ServiceFullName) + "\\InstallUtil.exe", "/i " + ServiceName + ".exe");
                    //LogUtil.Debug("RunExe:" + ServiceFullName + " ;return=" + ss);
                    ServiceHelper.SleepFunc(() => { services = null; return !flag || isServiceIsExisted(ServiceName); });
                }
                catch (Exception ex)
                {
                    LogUtil.Error(ex.ToString());
                    flag = false;
                }

            }
            return flag;
        }
        /// <summary>  
        /// 安装Windows服务  
        /// </summary>  
        /// <param name="stateSaver">集合</param>  
        /// <param name="filepath">程序文件路径</param>  
        public static bool InstallmyService(IDictionary stateSaver, string filepath)
        {
            try
            {
                //string[] cmdline = { };
                //TransactedInstaller transactedInstaller = new TransactedInstaller();
                //AssemblyInstaller assemblyInstaller = new AssemblyInstaller(filepath, cmdline);
                //transactedInstaller.Installers.Add(assemblyInstaller);
                //transactedInstaller.Install(new System.Collections.Hashtable());

                var AssemblyInstaller1 = new AssemblyInstaller();
                AssemblyInstaller1.UseNewContext = true;
                AssemblyInstaller1.Path = filepath;
                AssemblyInstaller1.Install(stateSaver);
                AssemblyInstaller1.Commit(stateSaver);
                AssemblyInstaller1.Dispose();
                return true;
            }
            catch (Exception ex)
            {
                LogUtil.Error(ex.ToString());
            }
            return false;
        }
        /// <summary>
        /// 安装服务
        /// </summary>
        /// <param name="p_Path">指定服务文件路径</param>
        /// <param name="p_ServiceName">返回安装完成后的服务名</param>
        /// <returns>安装信息 正确安装返回""</returns>
        public static string InsertService(string p_Path, ref string p_ServiceName)
        {
            if (!File.Exists(p_Path)) return "文件不存在！";
            p_ServiceName = "";
            FileInfo _InsertFile = new FileInfo(p_Path);
            IDictionary _SavedState = new Hashtable();
            try
            {
                //加载一个程序集，并运行其中的所有安装程序。
                AssemblyInstaller _AssemblyInstaller = new AssemblyInstaller(p_Path, new string[] { "/LogFile=" + _InsertFile.DirectoryName + "//" + _InsertFile.Name.Substring(0, _InsertFile.Name.Length - _InsertFile.Extension.Length) + ".log" });
                _AssemblyInstaller.UseNewContext = true;
                _AssemblyInstaller.Install(_SavedState);
                _AssemblyInstaller.Commit(_SavedState);
                Type[] _TypeList = _AssemblyInstaller.Assembly.GetTypes();//获取安装程序集类型集合
                for (int i = 0; i != _TypeList.Length; i++)
                {
                    if (_TypeList[i].BaseType.FullName == "System.Configuration.Install.Installer")
                    {
                        //找到System.Configuration.Install.Installer 类型
                        object _InsertObject = System.Activator.CreateInstance(_TypeList[i]);//创建类型实列
                        FieldInfo[] _FieldList = _TypeList[i].GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
                        for (int z = 0; z != _FieldList.Length; z++)
                        {
                            if (_FieldList[z].FieldType.FullName == "System.ServiceProcess.ServiceInstaller")
                            {
                                object _ServiceInsert = _FieldList[z].GetValue(_InsertObject);
                                if (_ServiceInsert != null)
                                {
                                    p_ServiceName = ((ServiceInstaller)_ServiceInsert).ServiceName;
                                    return "";
                                }
                            }
                        }
                    }
                }
                return "";
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }
        #endregion

        #region 卸载服务
        public static bool UninstallServiceSelf(string ServiceFullName)
        {
            bool flag = true;
            var ServiceName = GetFileName(ServiceFullName); 
            if (isServiceIsExisted(ServiceName))
            {
                try
                {
                    var ss = ServiceHelper.RunExe(ServiceFullName, "-u");
                    LogUtil.Debug("RunExe:" + ServiceFullName + " ;return=" + ss);
                    //Process process = new Process();
                    //process.StartInfo.FileName = ServiceFullName;
                    //process.StartInfo.Arguments = "\"-u\"";
                    //process.StartInfo.UseShellExecute = true; ;
                    ////启动  
                    //process.Start();
                    //Process.Start(ServiceFullName, "-u");
                    //for (int i = 0; i < 60; i++)
                    //{
                    //    System.Threading.Thread.Sleep(1000);
                    //    if (!isServiceIsExisted(ServiceName))
                    //    {
                    //        break;
                    //    }
                    //    if (i == 59)
                    //    {
                    //        flag = false;
                    //    }
                    //}
                }
                catch
                {
                    flag = false;
                }
            }
            return flag;
        }
        /// <summary>    
        /// 卸载服务    
        /// </summary>    
        public static bool UninstallService(string ServiceFullName)
        {
            bool flag = true;
            var ServiceName = GetFileName(ServiceFullName); 
            if (isServiceIsExisted(ServiceName))
            {
                try
                {
                    flag = UnInstallmyService(ServiceFullName);
                    // Funs.RunCmd(GetFilePath(ServiceFullName) + "\\InstallUtil.exe /u " + ServiceName + ".exe");
                    // var ss = Funs.RunExe(GetFilePath(ServiceFullName) + "\\InstallUtil.exe", "/u " + ServiceName + ".exe");
                    // LogUtil.Debug("RunExe:" + ServiceFullName + " ;return=" + ss);
                    ServiceHelper.SleepFunc(() => { services = null; return !flag || !isServiceIsExisted(ServiceName); });
                }
                catch (Exception ex)
                {
                    LogUtil.Error(ex.ToString());
                    flag = false;
                }
            }
            return flag;
        }
        /// <summary>  
        /// 卸载Windows服务  
        /// </summary>  
        /// <param name="filepath">程序文件路径</param>  
        public static bool UnInstallmyService(string filepath)
        {
            try
            {
                //string[] cmdline = { };
                //TransactedInstaller transactedInstaller = new TransactedInstaller();
                //AssemblyInstaller assemblyInstaller = new AssemblyInstaller(filepath, cmdline);
                //transactedInstaller.Installers.Add(assemblyInstaller);
                //transactedInstaller.Uninstall(null);

                var AssemblyInstaller1 = new AssemblyInstaller();
                AssemblyInstaller1.UseNewContext = true;
                AssemblyInstaller1.Path = filepath;
                AssemblyInstaller1.Uninstall(new Hashtable());
                AssemblyInstaller1.Dispose();
                return true;
            }
            catch (Exception ex)
            {
                LogUtil.Error(ex.ToString());
            }
            return false;
        }
        #endregion

        #region 启动服务
        ///// <summary>  
        ///// 启动服务  
        ///// </summary>  
        ///// <param name=" NameService ">服务名</param>  
        ///// <returns>存在返回 true,否则返回 false;</returns>  
        public static bool StartService(string serviceName)
        {
            bool flag = true;
            try
            {
                if (isServiceIsExisted(serviceName))
                {
                    System.ServiceProcess.ServiceController service = new System.ServiceProcess.ServiceController(serviceName);
                    if (service.Status != System.ServiceProcess.ServiceControllerStatus.Running && service.Status != System.ServiceProcess.ServiceControllerStatus.StartPending)
                    {
                        service.Start();
                        TimeSpan timeout = TimeSpan.FromMilliseconds(1000 * 10);
                        service.WaitForStatus(ServiceControllerStatus.Running, timeout);
                        //Funs.SleepFunc(() =>
                        //{
                        //    service.Refresh();
                        //    return service.Status == System.ServiceProcess.ServiceControllerStatus.Running;
                        //});
                    }
                }
            }
            catch (Exception ex)
            {
                flag = false;
                LogUtil.Error(ex.ToString());
            }
            return flag;
        }
        #endregion

        #region 停止服务
        ///// <summary>  
        ///// 停止服务  
        ///// </summary>  
        ///// <param name=" NameService ">服务名</param>  
        ///// <returns>存在返回 true,否则返回 false;</returns>  
        public static bool StopService(string serviceName)
        {
            bool flag = true;
            try
            {
                if (isServiceIsExisted(serviceName))
                {
                    System.ServiceProcess.ServiceController service = new System.ServiceProcess.ServiceController(serviceName);
                    if (service.Status == System.ServiceProcess.ServiceControllerStatus.Running)
                    {
                        service.Stop();
                        TimeSpan timeout = TimeSpan.FromMilliseconds(1000 * 10);
                        service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
                        //Funs.SleepFunc(() =>
                        //{
                        //    service.Refresh();
                        //    return service.Status == System.ServiceProcess.ServiceControllerStatus.Stopped;
                        //});
                    }
                }
            }
            catch (Exception ex)
            {
                flag = false;
                LogUtil.Error(ex.ToString());
            }
            return flag;
        }
        #endregion    
        
        #region 判断window服务是否启动
        /// <summary>    
        /// 判断某个Windows服务是否启动    
        /// </summary>    
        /// <returns></returns>    
        public static bool IsServiceStart(string serviceName)
        {
            bool bStartStatus = false;
            try
            {
                ServiceController psc = new ServiceController(serviceName);
                if (!psc.Status.Equals(ServiceControllerStatus.Stopped))
                {
                    bStartStatus = true;
                }

                return bStartStatus;
            }
            catch (Exception ex)
            {
                LogUtil.Error(ex.ToString());
            }
            return false;
        }
        #endregion

        #region  ChangeServiceStartType
        /// <summary>      
        /// 修改服务的启动项    
        /// </summary>      
        /// <param name="startType"> 2为自动,3为手动, 4 为禁用 </param>      
        /// <param name="serviceName"></param>      
        /// <returns></returns>      
        public static bool ChangeServiceStartType(int startType, string serviceName)
        {
            try
            {
                RegistryKey regist = Registry.LocalMachine;
                RegistryKey sysReg = regist.OpenSubKey("SYSTEM");
                RegistryKey currentControlSet = sysReg.OpenSubKey("CurrentControlSet");
                RegistryKey services = currentControlSet.OpenSubKey("Services");
                RegistryKey servicesName = services.OpenSubKey(serviceName, true);
                servicesName.SetValue("Start", startType);
            }
            catch (Exception ex)
            {
                LogUtil.Error(ex.ToString());
                return false;
            }
            return true;
        }
        #endregion  
        #region GetServiceStartType
        /// <summary>
        /// 获取服务启动类型 2为自动 3为手动 4 为禁用
        /// </summary>
        /// <param name="serviceName"></param>
        /// <returns></returns>
        public static string GetServiceStartType(string serviceName)
        {
            try
            {
                RegistryKey regist = Registry.LocalMachine;
                RegistryKey sysReg = regist.OpenSubKey("SYSTEM");
                RegistryKey currentControlSet = sysReg.OpenSubKey("CurrentControlSet");
                RegistryKey services = currentControlSet.OpenSubKey("Services");
                RegistryKey servicesName = services.OpenSubKey(serviceName, true);
                return servicesName.GetValue("Start").ToString();
            }
            catch (Exception ex)
            {
                LogUtil.Error(ex.ToString());
                return string.Empty;
            }
        }
        #endregion
        #region GetServiceStatus
        /// <summary>  
        /// 获取服务状态  
        /// </summary>  
        /// <param name=" NameService ">服务名</param>  
        /// <returns>返回服务状态</returns>  
        public static int GetServiceStatus(string NameService)
        {
            int ret = 0;
            try
            {
                ServiceController sc = new ServiceController(NameService);
                ret = Convert.ToInt16(sc.Status);
            }
            catch (Exception ex)
            {
                ret = 0;
                LogUtil.Error(ex.ToString());
            }

            return ret;
        }
        #endregion
        #region GetServiceName
        /// <summary>
        /// 获取Windows服务的名称
        /// </summary>
        /// <param name="serviceFileName">文件路径</param>
        /// <returns>服务名称</returns>
        public static string GetServiceName(string serviceFileName)
        {
            try
            {
                Assembly assembly = Assembly.Load(serviceFileName);
                Type[] types = assembly.GetTypes();
                foreach (Type myType in types)
                {
                    if (myType.IsClass && myType.BaseType == typeof(System.Configuration.Install.Installer))
                    {
                        FieldInfo[] fieldInfos = myType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Default | BindingFlags.Instance | BindingFlags.Static);
                        foreach (FieldInfo myFieldInfo in fieldInfos)
                        {
                            if (myFieldInfo.FieldType == typeof(System.ServiceProcess.ServiceInstaller))
                            {
                                ServiceInstaller serviceInstaller = (ServiceInstaller)myFieldInfo.GetValue(Activator.CreateInstance(myType));
                                return serviceInstaller.ServiceName;
                            }
                        }
                    }
                }
                return "";
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        #endregion
        #region GetWindowsServiceInstallPath
        /// <summary>  
        /// 获取服务安装路径  
        /// </summary>  
        /// <param name="ServiceName"></param>  
        /// <returns></returns>  
        public static string GetWindowsServiceInstallPath(string ServiceName)
        {
            string path = "";
            try
            {
                string key = @"SYSTEM\CurrentControlSet\Services\" + ServiceName;
                path = Registry.LocalMachine.OpenSubKey(key).GetValue("ImagePath").ToString();

                path = path.Replace("\"", string.Empty);//替换掉双引号    

                FileInfo fi = new FileInfo(path);
                path = fi.Directory.ToString();
            }
            catch (Exception ex)
            {
                path = "";
                LogUtil.Error(ex.ToString());
            }
            return path;
        }
        #endregion
        #region GetServiceVersion
        /// <summary>  
        /// 获取指定服务的版本号  
        /// </summary>  
        /// <param name="serviceName">服务名称</param>  
        /// <returns></returns>  
        public static string GetServiceVersion(string serviceName)
        {
            if (string.IsNullOrEmpty(serviceName))
            {
                return string.Empty;
            }
            try
            {
                string path = GetWindowsServiceInstallPath(serviceName) + "\\" + serviceName + ".exe";
                Assembly assembly = Assembly.Load(path);
                AssemblyName assemblyName = assembly.GetName();
                Version version = assemblyName.Version;
                return version.ToString();
            }
            catch (Exception ex)
            {
                LogUtil.Error(ex.ToString());
                return string.Empty;
            }
        }
        #endregion

        #region 获取文件名
        /// <summary>
        /// 获取文件名，不包括扩展名
        /// </summary>
        /// <param name="ServiceFullName"></param>
        /// <returns></returns>
        public static string GetFileName(string ServiceFullName)
        {
            if (!string.IsNullOrEmpty(ServiceFullName))
            {
                var ServiceName = ServiceFullName.Substring(ServiceFullName.LastIndexOf('\\') + 1);//只到程序名称，不带.exe
                return ServiceName.Substring(0, ServiceName.LastIndexOf('.'));
            }
            else return "";
        }
        /// <summary>
        /// 获取文件路径
        /// </summary>
        /// <param name="ServiceFullName"></param>
        /// <returns></returns>
        public static string GetFilePath(string ServiceFullName)
        {
            if (!string.IsNullOrEmpty(ServiceFullName))
                return ServiceFullName.Substring(0, ServiceFullName.LastIndexOf('\\') + 1);
            else return "";
        }
        #endregion
    }
}
